﻿using System;
using System.Collections.Generic;
using System.Linq;

using BEX.DataAccess;
using BEX.Core;
using BEX.Core.Exchange;

namespace BEX.RuleMonitor
{
    public class PercentageRule : AlertRule
    {
        public decimal Percent { get; set; }

        public int TimeSpan { get; set; }

        public PercentageRule()
        {
        }

        public PercentageRule(int ID)
        {
            LoadRule(ID);
        }

        public PercentageRule(ExchangeType exchange, CurrencyType basec, CurrencyType counterc, decimal percent, int timespan)
        {
            Percent = percent;
            _pair = new CurrencyPair() { Base = basec, Counter = counterc };
            SourceExchange = exchange;
            TimeSpan = timespan;

            LoadRule(exchange, basec, counterc, percent, timespan);
        }

        private bool LoadRule(ExchangeType exchange, CurrencyType basec, CurrencyType counterc, decimal percent, int timespan)
        {
            var res = false;

            var _context = new BTCDataClassesDataContext();

            var _a = (from acc in _context.GetTable<ALERT_RULE_PERCENTAGE>()
                                where (acc.EXCHANGE_ID == (int)(exchange)
                                                                  && acc.BASE_CURRENCY_ID == (int)(basec)
                                                                  && acc.COUNTER_CURRENCY_ID == (int)(counterc)
                                                                  && acc.PERCENT == percent
                                                                  && acc.TIMESPAN == timespan)
                                select acc).ToList<ALERT_RULE_PERCENTAGE>();

            if (null != _a && _a.Count > 0)
            {
                this._id = _a[0].ID;
                this.Percent = _a[0].PERCENT;
                this.TimeSpan = _a[0].TIMESPAN;
                this._pair = new CurrencyPair() { Base = (CurrencyType)_a[0].BASE_CURRENCY_ID, Counter = (CurrencyType)_a[0].COUNTER_CURRENCY_ID };
                this._sourceExchangeID = _a[0].EXCHANGE_ID;
                this.TimeSpan = _a[0].TIMESPAN;


                res = true;
            }

            return res;
        }

        private bool LoadRule(int ID)
        {
            var res = false;

            var _context = new BTCDataClassesDataContext();

            var _a = (from acc in _context.GetTable<ALERT_RULE_PERCENTAGE>()
                                where (acc.ID == ID)
                                select acc).ToList<ALERT_RULE_PERCENTAGE>();

            if (null != _a && _a.Count > 0)
            {
                this._id = _a[0].ID;
                this.Percent = _a[0].PERCENT;
                this.TimeSpan = _a[0].TIMESPAN;
                this._pair = new CurrencyPair() { Base = (CurrencyType)_a[0].BASE_CURRENCY_ID, Counter = (CurrencyType)_a[0].COUNTER_CURRENCY_ID };
                this._sourceExchangeID = _a[0].EXCHANGE_ID;

                res = true;
            }

            return res;
        }

        public override void AddAccount(int AccID)
        {
            var _context = new BTCDataClassesDataContext();

            var _rule = (from c in _context.GetTable<ACCOUNT_RULE_PERCENTAGE>()
                                                   where (c.RULE_ID == this.ID && c.ACCOUNT_ID == AccID)
                                                   select c).SingleOrDefault();

            if (null == _rule)
            {
                var _acc = GetAccountRuleTable();

                var _a = new ACCOUNT_RULE_PERCENTAGE();

                _a.ACCOUNT_ID = AccID;
                _a.RULE_ID = this.ID;

                _acc.InsertOnSubmit(_a);
                _acc.Context.SubmitChanges();
            }
        }

        public override void RemoveAccount(int AccID)
        {
            var _context = new BTCDataClassesDataContext();

            var _rule = (from c in _context.GetTable<ACCOUNT_RULE_PERCENTAGE>()
                                      where (c.RULE_ID == this.ID && c.ACCOUNT_ID == AccID)
                                      select c).Single();

            if (null != _rule)
            {
                _context.ACCOUNT_RULE_PERCENTAGEs.DeleteOnSubmit(_rule);
                _context.SubmitChanges();
            }
        }

        public override List<int> GetAccountIDList()
        {
            var res = new List<int>();

            var _context = new BTCDataClassesDataContext();

            var _l = (from acc in _context.GetTable<ACCOUNT_RULE_PERCENTAGE>()
                                where (acc.RULE_ID == _id)
                                select acc).ToList<ACCOUNT_RULE_PERCENTAGE>();

            foreach (ACCOUNT_RULE_PERCENTAGE _r in _l)
            {
                res.Add(_r.ACCOUNT_ID);
            }

            return res;
        }

        public override bool Test(Tick current)
        {
            if (current.ExchangeSource != this.SourceExchange)
            {
                throw new Exception("ExchangeSource mismatch in % rule");
            }
            
            var _max = TickDAL.GetMaximumSpot(this.SourceExchange, current, this.TimeSpan);
            var _min = TickDAL.GetMinSpot(this.SourceExchange, current, this.TimeSpan);

            if (null == _max || null == _min)
            {
                throw new Exception("Unable to determine Max or Min for % rule.  DO other ticks exist? (Exchange: " + this.SourceExchange.ToString() + " TimeSpan: " + this.TimeSpan.ToString() + ")");
            }

            var _p = ((Convert.ToDecimal(_max) - Convert.ToDecimal(_min)) / Convert.ToDecimal(_min)) * 100;

            if (_p >= Percent)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public static List<PercentageRule> GetListForAccount(int AcctID)
        {
            var _l = AlertRuleList();

            var _ids = GetRuleIDs(AcctID);

            var res = new List<PercentageRule>();

            foreach (ALERT_RULE_PERCENTAGE _a in _l)
            {
                if (_ids.Contains(_a.ID))
                {
                    res.Add(new PercentageRule(_a.ID));
                }
            }

            return res;
        }

        private static List<int> GetRuleIDs(int AcctID)
        {
            var res = new List<int>();

            var _context = new BTCDataClassesDataContext();

            var _l = (from acc in _context.GetTable<ACCOUNT_RULE_PERCENTAGE>()
                                where (acc.ACCOUNT_ID == AcctID)
                                select acc).ToList<ACCOUNT_RULE_PERCENTAGE>();

            foreach (ACCOUNT_RULE_PERCENTAGE _r in _l)
            {
                res.Add(_r.RULE_ID);
            }

            return res;
        }

        private static List<ALERT_RULE_PERCENTAGE> AlertRuleList()
        {
            var _context = new BTCDataClassesDataContext();

            return (from acc in _context.GetTable<ALERT_RULE_PERCENTAGE>()
                                    select acc).ToList<ALERT_RULE_PERCENTAGE>();
        }

        public bool Save()
        {
            var res = true;

            var _context = new BTCDataClassesDataContext();

            var _rule = (from c in _context.GetTable<ALERT_RULE_PERCENTAGE>()
                                                   where c.ID == this.ID
                                                   select c).SingleOrDefault();

            if (null == _rule)
            {
                var _acc = GetAlertRuleTable();
                var _a = new ALERT_RULE_PERCENTAGE();

                _a.EXCHANGE_ID = _sourceExchangeID;
                _a.PERCENT = Percent;
                _a.COUNTER_CURRENCY_ID = (int)_pair.Counter;
                _a.BASE_CURRENCY_ID = (int)_pair.Base;
                _a.TIMESPAN = TimeSpan;

                _acc.InsertOnSubmit(_a);
                _acc.Context.SubmitChanges();

                this.ID = _a.ID;
            }
            else
            {
                _rule.EXCHANGE_ID = _sourceExchangeID;

                _rule.COUNTER_CURRENCY_ID = (int)_pair.Counter;
                _rule.BASE_CURRENCY_ID = (int)_pair.Base;
                _rule.PERCENT = Percent;
                _rule.TIMESPAN = TimeSpan;

                _context.SubmitChanges();
            }

            return res;
        }

        private static System.Data.Linq.Table<ACCOUNT_RULE_PERCENTAGE> GetAccountRuleTable()
        {
            var _context = new BTCDataClassesDataContext();

            return _context.GetTable<ACCOUNT_RULE_PERCENTAGE>();
        }

        private static System.Data.Linq.Table<ALERT_RULE_PERCENTAGE> GetAlertRuleTable()
        {
            var _context = new BTCDataClassesDataContext();

            return _context.GetTable<ALERT_RULE_PERCENTAGE>();
        }

        public static List<PercentageRule> GetPercentRuleList()
        {
            var _l = AlertRuleList();

            var res = new List<PercentageRule>();

            foreach (ALERT_RULE_PERCENTAGE _a in _l)
            {
                res.Add(new PercentageRule(_a.ID));
            }

            return res;
        }
    }
}
